package com.demo.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.demo.entity.ExaminationRecordEntity;
import com.demo.entity.QuestionBankEntity;
import com.demo.mapper.StudentMapper;
import com.demo.mapper.TeacherMapper;
import com.demo.util.DelayTaskConsumer;
import com.demo.util.Redis;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 控制层，直接与用户交互。
 * 处理请求与响应。
 */
@RestController
public class TeacherController {


    Log log = LogFactory.getLog("三岁小仙仙");
    @Resource
    TeacherMapper teacherMapper;

    @Resource
    StudentMapper studentMapper;

    Jedis redis = Redis.getRedis();

    /**
     * 根据教师工号查询教师创建的考试记录
     *
     * @param teacherNumber 教师工号
     * @return 数组对象
     */
    @GetMapping("/autoGetExaminationRecord")
    public String autoGetExaminationRecord(String teacherNumber) {
        List<Map<String, String>> teacherCreateExamination = teacherMapper.findTeacherCreateExamination(teacherNumber);
        Set<String> classNumbers = new HashSet<>();
        for (int i = 0; i < teacherCreateExamination.size(); i++) {
            classNumbers.add(teacherCreateExamination.get(i).get("classNumber"));
        }

        for (String key : classNumbers) {
            int peopleNumber = teacherMapper.countClassPeopleNumber(key);
            for (int i = 0; i < teacherCreateExamination.size(); i++) {
                if (teacherCreateExamination.get(i).get("classNumber").equals(key))
                    teacherCreateExamination.get(i).put("classPeopleNumber", String.valueOf(peopleNumber));
            }
        }
        return JSON.toJSONString(teacherCreateExamination);
    }

    /**
     * 根据教师工号、班级号、课程名删除对应的考试记录
     *
     * @param data 封装数据
     * @return 删除数量 正常情况为1或0
     */
    @PostMapping("/deleteExamination")
    public int deleteExamination(String data) {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String teacherNumber = jsonObject.get("teacherNumber").toString();
        String classNumber = jsonObject.get("classNumber").toString();
        String coursesName = jsonObject.get("coursesName").toString();
        String questionBank = jsonObject.get("questionBank") == null ? null : jsonObject.get("questionBank").toString();

        // 1.删除考试记录表中的数据
        int deleteExamination = teacherMapper.deleteExamination(teacherNumber, classNumber, coursesName);
        // 2.删除班级中所属性的对应考试课程名
        teacherMapper.deleteCourse(classNumber, coursesName);
        // 3.判断用户是否已录入过试题库，若存在则删除对应试题库，若无则不做处理
        if (questionBank != null) {
            try {
                //有可能教师创建了考试，但没有录入试题。则DB没有试题库表
                teacherMapper.deleteTable(questionBank);
                //有可能没有学生参考考试，既没有触发学生作答答案录入功能。则数据库没有作答表。
                teacherMapper.deleteTable(classNumber + "-" + questionBank);
            } catch (Exception e) {
            }
            redis.del(questionBank);
            redis.del(classNumber + "-" + questionBank);
            DelayTaskConsumer.deleteRedisClassExamination(redis, classNumber, questionBank, coursesName, teacherNumber);
        }
        // 4.删除对应redis缓存中的数据
        if (redis.exists(classNumber)) {
            String JsonString = redis.get(classNumber);
            JSONArray jsonArray = JSONArray.parseArray(JsonString);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject object = JSONObject.parseObject(jsonArray.get(i).toString());
                if (object.get("teacherNumber").equals(teacherNumber) && object.get("coursesName").equals(coursesName)) {
                    jsonArray.remove(i);
                }
            }
            redis.del(classNumber);
            if (jsonArray.size() == 0) {
                redis.del(classNumber);
            } else {
                redis.set(classNumber, jsonArray.toJSONString());
            }
        }
        return deleteExamination;
    }

    /**
     * 获取班级列表
     *
     * @return json班级列表
     */
    @GetMapping("/teacherGetClassList")
    private String teacherGetClassList() {
        return JSON.toJSONString(teacherMapper.getAllClassList("classManage"));
    }

    /**
     * 创建考试课程
     *
     * @param data 课程所属班级
     * @return true或错误消息
     */
    @PostMapping("/createCoursesClass")
    public String createCoursesClass(String data) {
        // 添加教师创建考试记录: 教师工号，班级号，课程名，开始时间，结束时间，学生试题分析权限
        ExaminationRecordEntity recordEntity = JSONObject.parseObject(data, ExaminationRecordEntity.class);
        int addCourse = -1;
        try {
            addCourse = teacherMapper.addCourse(recordEntity.getClassNumber(), recordEntity.getCoursesName());
        } catch (Exception e) {
            return "false";
        }
        if (addCourse != -1) {
            Object isNull = teacherMapper.checkCountExaminationRecordIsNull();
            int count = 0;
            if (isNull != null) {
                count = teacherMapper.countExaminationRecord();
            }
            recordEntity.setId(++count);
            int createCoursesClass = teacherMapper.createCoursesClass(recordEntity);
            if (redis.exists(recordEntity.getClassNumber())) {
                String examinationTime = redis.get(recordEntity.getClassNumber());
                JSONArray jsonArray = JSONArray.parseArray(examinationTime);
                JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(recordEntity, SerializerFeature.WriteMapNullValue));
                jsonArray.add(jsonObject);
                redis.set(recordEntity.getClassNumber(), JSON.toJSONString(jsonArray));
            } else {
                // json对象 转 json数组对象 存jedis
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(JSON.toJSONString(recordEntity, SerializerFeature.WriteMapNullValue));
                redis.set(recordEntity.getClassNumber(), JSON.toJSONString(jsonArray));
            }
        }
        return "true";
    }

    /**
     * 查询试题库所有试题
     *
     * @param questionBankName 试题库名
     * @return tableAll
     */
    @PostMapping("/autoGetQuestionBankInfo")
    public String autoGetQuestionBankInfo(String questionBankName) {
        // 根据试题库号查询试题库所有信息，有两种方法：
        // 1.读取缓存中的试题库中的信息，当前若是存在的话（因为第一个试题库都有过期时间），这样可以更快的读取记录
        // 2.读取数据库中的记录信息，当缓存中不存在的时候，就进数据库读取
        // 3.若都没有处理返回信息
        if (redis.exists(questionBankName)) {
            return JSON.toJSONString(JSON.parseArray(redis.get(questionBankName)));
        } else {
            try {
                return JSON.toJSONString(teacherMapper.getAllClassList(questionBankName));
            } catch (Exception e) {
                return JSON.toJSONString(new String[]{});
            }
        }
    }

    /**
     * 添加/更新试题库
     *
     * @param id            教师创建的考试记录表中的对应id号
     * @param questionsList 数组对象
     * @return true或失败消息
     */
    @PostMapping("/saveQuestionBank")
    public String saveQuestionBank(String id, String questionsList) throws ParseException {
        List<QuestionBankEntity> list = JSONArray.parseArray(questionsList, QuestionBankEntity.class);
        // 1.查询考试记录表中对应的班级试题库是否已经创建试题库
        ExaminationRecordEntity examinationRecordEntity = teacherMapper.queryExaminationRecordById(id);
        // 2.计算考试结束时间，缓存中需要设置，这里提前选计算好，后面直接用
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date parse = sdf.parse(examinationRecordEntity.getEndTime());
        // 2.1判断老师提交试题时，是否已经过开考时间，过了则不能创建考试试题
        Date startTime = sdf.parse(examinationRecordEntity.getStartTime());
        if (startTime.getTime() <= new Date().getTime()) return "试题创建失败";
        // 3.计算出来是毫秒，实际需要秒单位 / 1000 , 最后四舍五入
        long effectiveTime = Math.round((parse.getTime() - new Date().getTime()) / 1000);

        //考试记录表中没有试题库记录
        if (examinationRecordEntity.getQuestionBank() == null) {
            // 4.创建随机试题库号
            Random random = new Random();
            StringBuffer questionBank = new StringBuffer();
            for (int i = 0; i < 10; i++) {
                questionBank.append(random.nextInt(10));
            }
            // 5.创建试题库表
            String res = "试题创建失败";
            try {
                teacherMapper.createQuestionBank(questionBank.toString());
            } catch (Exception e) {
                return res;
            }
            // 6.将试题信息批量插入到数据库中，持久化存储
            res = String.valueOf(teacherMapper.addQuestionList(questionBank.toString(), list));
            // 7.在考试记录表中 录入本课程对应的试题库号
            examinationRecordEntity.setQuestionBank(questionBank.toString());
            teacherMapper.updateCoursesClass(examinationRecordEntity);
            // 8.将试题库号录入数据库后，同时录入缓存redis中
            String jsonString = redis.get(examinationRecordEntity.getClassNumber());
            JSONArray jsonArray = JSONArray.parseArray(jsonString);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = JSONObject.parseObject(jsonArray.getString(i));
                if (jsonObject.get("teacherNumber").equals(examinationRecordEntity.getTeacherNumber()) && jsonObject.get("coursesName").equals(examinationRecordEntity.getCoursesName())) {
                    jsonObject.put("questionBank", examinationRecordEntity.getQuestionBank());
                    jsonArray.remove(i);
                    jsonArray.add(i, jsonObject);
                }
            }
            redis.set(examinationRecordEntity.getClassNumber(), JSON.toJSONString(jsonArray));
            // 分隔线------------下面的set 和 上面的set是对不一样的缓存key操作，不要看错了
            // 9.将试题库存入缓存redis中, 此处不用判断该试题库是否存在，因为该试题库与数据库一一对应
            redis.set(examinationRecordEntity.getQuestionBank(), JSON.toJSONString(list));
            // 10.设置一下过期时间，就是考试结束时间
            redis.expire(examinationRecordEntity.getQuestionBank(), (int) effectiveTime + 600);
            return "true";
        } else {
            // 教师操作了 更新试题库
            // 1.这里为了简单，先删除对应试题库中所有数据
            if (checkQuestionBankIsDigit(examinationRecordEntity.getQuestionBank()))
                teacherMapper.deleteQuestionBank(examinationRecordEntity.getQuestionBank());
            else return "false";
            // 3.将获取到的最新试题信息重新批量插入到试题库表中
            boolean updateQuestionBank = teacherMapper.addQuestionList(examinationRecordEntity.getQuestionBank(), list);

            // 4.重新将信息存入缓存中, 判断一下保存成功没有
            if (updateQuestionBank) {
                // 5.执行到了这一步，不用判断是否存在缓存中的对应试题库了，因为，这是在有试题库的情况下才进入到这里的else
                //redis.del(examinationRecordEntity.getQuestionBank());
                // 6.直接将list数组对象，转换为字符数组对象
                redis.set(examinationRecordEntity.getQuestionBank(), JSON.toJSONString(list));
                // 7.设置一下过期时间，就是考试结束时间
                redis.expire(examinationRecordEntity.getQuestionBank(), (int) effectiveTime + 600);
            }
            // 8.返回用户操作情况
            return "true";
        }
    }

    /**
     * 检查试题库是否合法
     *
     * @param questionBank 试题库号
     * @return true、false
     */
    private boolean checkQuestionBankIsDigit(String questionBank) {
        if (questionBank.length() != 10) return false;
        for (int i = 0; i < questionBank.length(); i++) {
            if (!Character.isDigit(questionBank.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据试题库名，删除试题库中所有试题
     *
     * @param questionBankName 试题库名
     */
    @PostMapping("/clearAllQuestionBank")
    public boolean clearAllQuestionBank(String questionBankName) {
        if (checkQuestionBankIsDigit(questionBankName)) {
            teacherMapper.deleteQuestionBank(questionBankName);
            redis.set(questionBankName, "");
        } else return false;
        return true;
    }

    /**
     * 获取班级学生科目成绩
     *
     * @param classNumber 班级号
     * @param coursesName 科目
     * @return json数组
     */
    @PostMapping("/autoGetClassStudentCoursesResult")
    public String autoGetClassStudentCoursesResult(String classNumber, String coursesName) {
        List<Map<String, String>> list = teacherMapper.autoGetClassStudentCoursesResult(classNumber, coursesName);
        /**
         * public static String toJSONString(Object object, SerializerFeature… features)：
         * 该方法将实体对象转换成Json字符串时，如果不传递参数SerializerFeature.WriteMapNullValue，则忽略值为null的属性。
         */
        return JSON.toJSONString(list, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 编辑考试记录信息 -- 这里的编辑考试记录是修改考试时间
     *
     * @param data 封装对象
     * @return 更新数
     */
    @PostMapping("/editExamination")
    public int editExamination(String data) throws ParseException {
        JSONObject jsonObject = JSONObject.parseObject(data);
        String teacherNumber = jsonObject.get("teacherNumber").toString();
        String classNumber = jsonObject.get("classNumber").toString();
        String coursesName = jsonObject.get("coursesName").toString();
        String startTime = jsonObject.get("startTime").toString();
        String endTime = jsonObject.get("endTime").toString();
        int update = teacherMapper.editExamination(teacherNumber, classNumber, coursesName, startTime, endTime);
        // 不用判断缓存中是否存在对应班级号记录，该编辑方法的前提条件是 有考试记录
        String jsonString = redis.get(classNumber);
        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        String questionBank = null;
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = JSONObject.parseObject(jsonArray.get(i).toString());
            if (object.get("teacherNumber").equals(teacherNumber) && object.get("coursesName").equals(coursesName)) {
                Set<String> strings = object.keySet();
                for (String s : strings) {
                    if (s.equals("questionBank")) {
                        questionBank = object.get("questionBank").toString();
                    }
                }
                object.put("startTime", startTime);
                object.put("endTime", endTime);
                jsonArray.remove(i);
                jsonArray.add(i, object);
            }
        }
        redis.set(classNumber, jsonArray.toJSONString());
        // 既然编辑了考试时间，则 对应的试题库过期时间也需要更新，但，这也有一个可能，教师根本没有创建试题库，却修改了
        // 考试时间，所以在这里需要判断是否存在试题库, 如何获取，根据更新的考试记录信息中获取 试题库号，若有则存在试题库号
        if (questionBank != null) { // 在考试记录表中，记录有一个试题库
            if (redis.exists(questionBank)) { // 双重判断一下，表中有记录，怕万一缓存里没有
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                Date parse = sdf.parse(endTime);
                // 3.计算出来是毫秒，实际需要秒单位 / 1000 , 最后四舍五入
                long effectiveTime = Math.round((parse.getTime() - new Date().getTime()) / 1000);
                redis.expire(questionBank, (int) effectiveTime);
            }
        }
        return update;
    }

    /**
     * 使用在 获取试题库信息
     * 根据表名，查询表中所有数据 -- 可公共
     *
     * @param tableName 表名
     * @return 数组对象
     * 该方法主要使用在了 教师试题分析功能模块中，用于获取【试题库】和【作答库】这两个表
     */
    @PostMapping("/getQuestion")
    public Object getQuestion(String tableName) {
        try {
            return teacherMapper.getAllClassList(tableName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用在 获取作答库信息 并 联合班级表查询学生姓名
     *
     * @param classNumber  班级表名
     * @param questionBank 试题库名
     * @return 数组对象
     */
    @PostMapping("/getAnswerLibrary")
    public Object getAnswerLibrary(String classNumber, String questionBank, String studentNumber) {
        try {
            return studentMapper.getAnswerLibrary(classNumber, questionBank, studentNumber);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 教师更新学生查看试题分析权限
     *
     * @param id
     * @param questionBank
     * @param status
     * @return
     */
    @PostMapping("/upStudentPreview")
    public boolean upStudentPreview(String id, String questionBank, boolean status) {
        try {
            return teacherMapper.upStudentPreview(id, questionBank, status);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 模糊查找班级
     *
     * @param className 班级名称
     * @return 班级列表
     */
    @PostMapping("/searchClass")
    public Object searchClass(String className, String teacherNumber) {
        List<Map> mapList = teacherMapper.searchClass(className);
        return mapList;
    }

    /**
     * 查询签到记录中的课程名
     *
     * @param classNumber   班级号
     * @param teacherNumber 教师编号
     * @return list
     */
    @PostMapping("/queryClassSignInRecordCourseName")
    public Object queryClassSignInRecordCourseName(String classNumber, String teacherNumber) {
        List<Map> list = teacherMapper.queryClassSignInRecordCourseName(classNumber, teacherNumber);
        return list;
    }
}
